package com.young.common.config;

import com.young.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.Ordered;
import org.springframework.format.FormatterRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * webmvc统一配置处理
 * @author imrookie
 * @date 2018/10/1
 */
@Component
@ConfigurationProperties(prefix="young.interceptor")
public class YoungWebMvcConfig extends WebMvcConfigurationSupport {

    Logger logger = LoggerFactory.getLogger(YoungWebMvcConfig.class);

    @Resource
    DateFormatter dateFormatter;

    //拦截器的bean,多个使用逗号拼接
    private String beanNames;

    //默认访问地址
    private String welcomeUrl;

    /**
     * 默认拦截器排除路径
     * 这里配置的路径默认不走拦截器,通常是一些静态资源
     * 例如: /static/**, /jo/**
     */
    private String[] defaultInterceptorExcludePathPatterns;

    /**
     * 资源映射
     * key有2个:
     * 1.patterns: 资源访问路径, 例如: /static/**
     * 2.locations: 对应的实际地址, 例如: classpath:/static/
     */
    private List<Map<String, String[]>> resourceMappers;
    //对应上面的patterns常量
    private static final String RESOURCE_MAPPER_KEY_PATTERNS = "patterns";
    //对应上面的locations常量
    private static final String RESOURCE_MAPPER_KEY_LOCATIONS = "locations";

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        if (StringUtils.isBlank(beanNames)){
            logger.info("[YoungWebMvc全局配置-拦截器] 未发现拦截器bean配置,若需开启拦截器,请配置[young.interceptor.beanNames],多个拦截器bean使用逗号拼接");
        }

        String[] beanNameArr = beanNames.split(",");
        if (beanNameArr == null || beanNameArr.length == 0){
            logger.error("[YoungWebMvc全局配置-拦截器] 参数[young.interceptor.beanNames={}]解析为数组失败", beanNames);
        }
        super.addInterceptors(registry);

        //遍历,装载拦截器配置
        for (String beanName : beanNameArr){
            if (StringUtils.isNotBlank(beanName)){
                //根据配置获取bean
                Object interceptor = SpringContextHolder.getBean(beanName);
                if (interceptor == null){
                    logger.error("[YoungWebMvc全局配置-拦截器] 根据beanName={}获取bean实例失败", beanName);
                    throw new RuntimeException("根据beanName=" + beanName + "获取bean实例失败");
                }
                InterceptorRegistration interceptorRegistration = null;
                if (interceptor instanceof ICommonInterceptor){//公共拦截器接口
                    //拦截器自行注册
                    interceptorRegistration = ((ICommonInterceptor) interceptor).addInterceptors(registry);
                } else if (interceptor instanceof HandlerInterceptor){//spring mvc原始拦截器接口
                    //注册拦截器,默认url模式为/*,默认排除static和page下的静态文件
                    interceptorRegistration = registry.addInterceptor((HandlerInterceptor) interceptor).addPathPatterns("/**");
                } else {
                    logger.warn("[YoungWebMvc全局配置-拦截器] 未知的拦截器实例类型:{},目前支持类型为:HandlerInterceptor,ICommonInterceptor", interceptor.getClass().getName());
                }
                //设置默认排除路径
                if (interceptorRegistration != null && this.defaultInterceptorExcludePathPatterns != null && this.defaultInterceptorExcludePathPatterns.length > 0) {
                    interceptorRegistration.excludePathPatterns(this.defaultInterceptorExcludePathPatterns);
                    logger.debug("[YoungWebMvc全局配置-拦截器] 为拦截器[{}]设置默认排除路径:{},对应配置项[young.interceptor.defaultInterceptorExcludePathPatterns]", beanName, this.defaultInterceptorExcludePathPatterns);
                }
                logger.info("[YoungWebMvc全局配置-拦截器] 拦截器[{}]注册完成.", beanName);
            }else {
                logger.warn("[YoungWebMvc全局配置-拦截器] bean设置中存在beanName为空:[young.interceptor.beanNames={}]", beanNames);
            }
        }
    }

    /**
     * 注册静态资源
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //第一个方法设置访问路径前缀，第二个方法设置资源路径
        //静态资源
        //registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        //页面
        //registry.addResourceHandler("/page/**").addResourceLocations("classpath:/page/");
        //registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/");
        logger.debug("[YoungWebMvc全局配置-注册静态资源] 开始注册静态资源.");
        if (this.resourceMappers == null || this.resourceMappers.isEmpty()) {
            logger.warn("[YoungWebMvc全局配置-注册静态资源] 资源映射配置为空,请确认是否真的不需配置静态资源映射,对应配置项[young.interceptor.resource-mappers]");
            return;
        }
        for (Map<String, String[]> map : this.resourceMappers) {
            if (map == null || map.isEmpty()) {
                continue;
            }
            if (!map.containsKey(RESOURCE_MAPPER_KEY_PATTERNS) || !map.containsKey(RESOURCE_MAPPER_KEY_LOCATIONS)) {
                logger.warn("[YoungWebMvc全局配置-注册静态资源] 资源映射配置项无效,请检查配置是否正确");
                continue;
            }
            registry.addResourceHandler(map.get(RESOURCE_MAPPER_KEY_PATTERNS)).addResourceLocations(map.get(RESOURCE_MAPPER_KEY_LOCATIONS));
            logger.info("[YoungWebMvc全局配置-注册静态资源] 成功注册静态资源,{}={},{}={}", RESOURCE_MAPPER_KEY_PATTERNS, map.get(RESOURCE_MAPPER_KEY_PATTERNS), RESOURCE_MAPPER_KEY_LOCATIONS, map.get(RESOURCE_MAPPER_KEY_LOCATIONS));
        }
        logger.debug("[YoungWebMvc全局配置-注册静态资源] 注册静态资源完毕.");
    }

    /**
     * 注册视图控制器
     * @param registry
     */
    protected void addViewControllers(ViewControllerRegistry registry) {
        if (StringUtils.isNotBlank(welcomeUrl)) {
            registry.addViewController("/").setViewName(welcomeUrl);//"forward:" +
            registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        }
    }

    /**
     * 格式化
     * @param registry
     */
    @Override
    protected void addFormatters(FormatterRegistry registry) {
        //时间格式化
        registry.addFormatter(dateFormatter);
    }

    public String getBeanNames() {
        return beanNames;
    }

    public void setBeanNames(String beanNames) {
        this.beanNames = beanNames;
    }

    public String getWelcomeUrl() {
        return welcomeUrl;
    }

    public void setWelcomeUrl(String welcomeUrl) {
        this.welcomeUrl = welcomeUrl;
    }

    public String[] getDefaultInterceptorExcludePathPatterns() {
        return defaultInterceptorExcludePathPatterns;
    }

    public void setDefaultInterceptorExcludePathPatterns(String[] defaultInterceptorExcludePathPatterns) {
        this.defaultInterceptorExcludePathPatterns = defaultInterceptorExcludePathPatterns;
    }

    public List<Map<String, String[]>> getResourceMappers() {
        return resourceMappers;
    }

    public void setResourceMappers(List<Map<String, String[]>> resourceMappers) {
        this.resourceMappers = resourceMappers;
    }
}
